popover: Add a "modal" boolean property to GtkPopover
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 10 Jan 2014 11:04:17 +0000 (12:04 +0100)
committerCarlos Garnacho <carlosg@gnome.org>
Wed, 22 Jan 2014 16:10:06 +0000 (17:10 +0100)
This property is TRUE by default, when a popover is modal, it
will automatically set a GTK+ grab on the popover, and grab
the keyboard focus into the popover.

demos/gtk-demo/popover.c
docs/reference/gtk/gtk3-sections.txt
gtk/gtkentry.c
gtk/gtkpopover.c
gtk/gtkpopover.h
gtk/gtktextview.c

index 4247f57606cd3641fd8ddebef0a759946aeee6a0..cb2c6b9765a9d5af2d90ce52af4dd69943788338 100644 (file)
@@ -92,7 +92,6 @@ entry_icon_press_cb (GtkEntry             *entry,
   gtk_entry_get_icon_area (entry, icon_pos, &rect);
   gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
   gtk_widget_show (popover);
-  gtk_grab_add (popover);
 
   g_object_set_data (G_OBJECT (entry), "popover-icon-pos",
                      GUINT_TO_POINTER (icon_pos));
@@ -126,7 +125,6 @@ day_selected_cb (GtkCalendar *calendar,
   gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
 
   gtk_widget_show (popover);
-  gtk_grab_add (popover);
 
   gdk_event_free (event);
 }
@@ -151,6 +149,7 @@ do_popover (GtkWidget *do_widget)
       popover = create_popover (widget,
                                 gtk_label_new ("This popover does not grab input"),
                                 GTK_POS_TOP);
+      gtk_popover_set_modal (GTK_POPOVER (popover), FALSE);
       g_signal_connect (widget, "toggled",
                         G_CALLBACK (toggle_changed_cb), popover);
       gtk_container_add (GTK_CONTAINER (box), widget);
index 91f4f484be63a3309b5aec9507680b594974adf2..d058a85c4bc95a609bf9989066bfe2d6380628d9 100644 (file)
@@ -7869,4 +7869,6 @@ gtk_popover_set_pointing_to
 gtk_popover_get_pointing_to
 gtk_popover_set_position
 gtk_popover_get_position
+gtk_popover_set_modal
+gtk_popover_get_modal
 </SECTION>
index 8ff06fd5c4cf509b70ce534244c14d5d4c8779a0..90868242a7fd204a093f3b67f1f83fa1a336d2b4 100644 (file)
@@ -2674,6 +2674,7 @@ gtk_entry_init (GtkEntry *entry)
   gtk_widget_set_size_request (priv->magnifier, 100, 60);
   _gtk_magnifier_set_magnification (GTK_MAGNIFIER (priv->magnifier), 2.0);
   priv->magnifier_popover = gtk_popover_new (GTK_WIDGET (entry));
+  gtk_popover_set_modal (GTK_POPOVER (priv->magnifier_popover), FALSE);
   gtk_container_add (GTK_CONTAINER (priv->magnifier_popover),
                      priv->magnifier);
   gtk_container_set_border_width (GTK_CONTAINER (priv->magnifier_popover), 4);
@@ -9473,6 +9474,7 @@ bubble_targets_received (GtkClipboard     *clipboard,
   priv->selection_bubble = gtk_popover_new (GTK_WIDGET (entry));
   gtk_popover_set_position (GTK_POPOVER (priv->selection_bubble),
                             GTK_POS_TOP);
+  gtk_popover_set_modal (GTK_POPOVER (priv->selection_bubble), FALSE);
 
   toolbar = GTK_WIDGET (gtk_toolbar_new ());
   gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT);
index e425641ad3041bd4040b0b1e6f72fa4254aa008a..6062dcaf7cbfb2b8b1f3fb501482e9e586afda4c 100644 (file)
@@ -53,7 +53,8 @@ typedef struct _GtkPopoverPrivate GtkPopoverPrivate;
 enum {
   PROP_RELATIVE_TO = 1,
   PROP_POINTING_TO,
-  PROP_POSITION
+  PROP_POSITION,
+  PROP_MODAL
 };
 
 struct _GtkPopoverPrivate
@@ -68,6 +69,7 @@ struct _GtkPopoverPrivate
   guint preferred_position : 2;
   guint final_position     : 2;
   guint current_position   : 2;
+  guint modal              : 1;
 };
 
 static GQuark quark_widget_popovers = 0;
@@ -81,13 +83,15 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkPopover, gtk_popover, GTK_TYPE_BIN)
 static void
 gtk_popover_init (GtkPopover *popover)
 {
+  GtkPopoverPrivate *priv;
   GtkWidget *widget;
 
   widget = GTK_WIDGET (popover);
   gtk_widget_set_has_window (widget, TRUE);
-  popover->priv = gtk_popover_get_instance_private (popover);
+  popover->priv = priv = gtk_popover_get_instance_private (popover);
   gtk_style_context_add_class (gtk_widget_get_style_context (widget),
                                GTK_STYLE_CLASS_OSD);
+  priv->modal = TRUE;
 }
 
 static void
@@ -110,6 +114,10 @@ gtk_popover_set_property (GObject      *object,
       gtk_popover_set_position (GTK_POPOVER (object),
                                 g_value_get_enum (value));
       break;
+    case PROP_MODAL:
+      gtk_popover_set_modal (GTK_POPOVER (object),
+                             g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -134,6 +142,9 @@ gtk_popover_get_property (GObject    *object,
     case PROP_POSITION:
       g_value_set_enum (value, priv->preferred_position);
       break;
+    case PROP_MODAL:
+      g_value_set_boolean (value, priv->modal);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -206,9 +217,18 @@ gtk_popover_realize (GtkWidget *widget)
 static void
 gtk_popover_map (GtkWidget *widget)
 {
+  GtkPopoverPrivate *priv;
+
+  priv = GTK_POPOVER (widget)->priv;
   GTK_WIDGET_CLASS (gtk_popover_parent_class)->map (widget);
   gdk_window_show (gtk_widget_get_window (widget));
   gtk_popover_update_position (GTK_POPOVER (widget));
+
+  if (priv->modal)
+    {
+      gtk_grab_add (widget);
+      gtk_widget_grab_focus (widget);
+    }
 }
 
 static void
@@ -881,6 +901,22 @@ gtk_popover_class_init (GtkPopoverClass *klass)
                                                       GTK_TYPE_POSITION_TYPE, GTK_POS_TOP,
                                                       GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
+  /**
+   * GtkPopover:modal
+   *
+   * Sets whether the popover is modal (so other elements in the window are
+   * not usable while the popover is visible).
+   *
+   * Since: 3.12
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_MODAL,
+                                   g_param_spec_boolean ("modal",
+                                                         P_("Modal"),
+                                                         P_("Whether the popover is modal"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
+
   quark_widget_popovers = g_quark_from_static_string ("gtk-quark-widget-popovers");
 }
 
@@ -1240,3 +1276,67 @@ gtk_popover_get_position (GtkPopover *popover)
 
   return priv->preferred_position;
 }
+
+/**
+ * gtk_popover_set_modal:
+ * @popover: a #GtkPopover
+ * @modal: #TRUE to make popover claim all input within the toplevel
+ *
+ * Sets whether @popover is modal, a modal popover will grab all input
+ * within the toplevel and grab the keyboard focus on it when being
+ * displayed. Clicking outside the popover area or pressing Esc will
+ * dismiss the popover and ungrab input.
+ *
+ * Since: 3.12
+ **/
+void
+gtk_popover_set_modal (GtkPopover *popover,
+                       gboolean    modal)
+{
+  GtkPopoverPrivate *priv;
+
+  g_return_if_fail (GTK_IS_POPOVER (popover));
+
+  priv = popover->priv;
+
+  if ((priv->modal == TRUE) == (modal == TRUE))
+    return;
+
+  priv->modal = (modal != FALSE);
+
+  if (gtk_widget_is_visible (GTK_WIDGET (popover)))
+    {
+      if (priv->modal)
+        {
+          gtk_grab_add (GTK_WIDGET (popover));
+          gtk_widget_grab_focus (GTK_WIDGET (popover));
+        }
+      else
+        gtk_grab_remove (GTK_WIDGET (popover));
+    }
+
+  g_object_notify (G_OBJECT (popover), "modal");
+}
+
+/**
+ * gtk_popover_get_modal:
+ * @popover: a #GtkPopover
+ *
+ * Returns whether the popover is modal, see gtk_popover_set_modal to
+ * see the implications of this.
+ *
+ * Returns: #TRUE if @popover is modal
+ *
+ * Since: 3.12
+ **/
+gboolean
+gtk_popover_get_modal (GtkPopover *popover)
+{
+  GtkPopoverPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_POPOVER (popover), FALSE);
+
+  priv = popover->priv;
+
+  return priv->modal;
+}
index 231dcb0fe181b8d9ff59f9fa1cc3d59eeba07333..37b06553372d2d27765a554d4518504f2771471e 100644 (file)
@@ -73,6 +73,12 @@ void            gtk_popover_set_position    (GtkPopover            *popover,
 GDK_AVAILABLE_IN_3_12
 GtkPositionType gtk_popover_get_position    (GtkPopover            *popover);
 
+GDK_AVAILABLE_IN_3_12
+void            gtk_popover_set_modal       (GtkPopover            *popover,
+                                             gboolean               modal);
+GDK_AVAILABLE_IN_3_12
+gboolean        gtk_popover_get_modal       (GtkPopover            *popover);
+
 G_END_DECLS
 
 #endif /* __GTK_POPOVER_H__ */
index 1fa6945095fb74cc0a67247a0cf57dbeabc90a79..0ec8319903613d29481b00d5875dc69197ec218b 100644 (file)
@@ -1551,6 +1551,7 @@ gtk_text_view_init (GtkTextView *text_view)
   gtk_widget_set_size_request (priv->magnifier, 100, 60);
   _gtk_magnifier_set_magnification (GTK_MAGNIFIER (priv->magnifier), 2.0);
   priv->magnifier_popover = gtk_popover_new (widget);
+  gtk_popover_set_modal (GTK_POPOVER (priv->magnifier_popover), FALSE);
   gtk_container_add (GTK_CONTAINER (priv->magnifier_popover),
                      priv->magnifier);
   gtk_container_set_border_width (GTK_CONTAINER (priv->magnifier_popover), 4);
@@ -8947,6 +8948,7 @@ bubble_targets_received (GtkClipboard     *clipboard,
   priv->selection_bubble = gtk_popover_new (GTK_WIDGET (text_view));
   gtk_popover_set_position (GTK_POPOVER (priv->selection_bubble),
                             GTK_POS_TOP);
+  gtk_popover_set_modal (GTK_POPOVER (priv->selection_bubble), FALSE);
 
   toolbar = GTK_WIDGET (gtk_toolbar_new ());
   gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT);